package com.example.mail;

import com.example.mail.utils.RandomUtil;
import com.sun.jdi.Bootstrap;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import jakarta.mail.internet.MimeMessage;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

// Spring 官方文档 https://docs.springjava.cn/spring-framework/reference/integration/email.html
// Spring Boot 官方文档 https://docs.springjava.cn/spring-boot/reference/io/email.html
@Slf4j
@SpringBootTest
public class MailApplicationTest {

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private RandomUtil randomUtil;

    // 从配置文件读取发件人邮箱
    @Value("${spring.mail.username}")
    private String senderFrom;

    /**
     * 发送简单文本邮件
     */
    @Test
    public void sendEmailWithEasy() {
        // 创建一个邮件信息对象，用于封装邮件信息
        SimpleMailMessage message = new SimpleMailMessage();
        // 一般来说，发送邮件的下面参数都有前端直接传入。
        // 发件人
        message.setFrom(senderFrom);
        // 收件人
        message.setTo("3960981061@qq.com");
        // 邮件主题，相当于邮件的目的精炼介绍
        message.setSubject("测试邮件发送主题");
        // 邮件内容
        message.setText("Hello World From Spring Boot Application");
        try {
            javaMailSender.send(message);
        } catch (Exception e) {
            log.error("发送邮件出错，错误信息为:[{}]",e.getMessage(),e);
        }
    }

    /**
     * 发送带有附件的邮件
     */
    @Test
    public void sendEmailWithNotEasy() throws Exception {
        // 创建一个邮件信息对象，用于封装邮件信息
        MimeMessage message = javaMailSender.createMimeMessage();
        // 创建 MimeMessageHelper，指定 boolean multipart 参数为 true
        // MimeMessageHelper 对象用于帮助邮件对象设值发送参数
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        // 发件人邮箱和名称
        helper.setFrom(senderFrom, "龙茶清欢");
        // 收件人邮箱
        helper.setTo("3960981061@qq.com");
        // 邮件标题
        helper.setSubject("测试邮件发送主题");
        // 邮件正文，第二个参数表示是否是HTML正文。我们也可以在这里放入一个精美的HTML页面
        helper.setText("你好，这是 龙茶清欢 的邮件发送测试文档！<br/> 请尽快下载！", true);
        // 添加一个附件，指定附件名称、文件的 Inputstream 流 以及 Content-Type
        // 可选的有 addAttachment 添加附件   addInline 添加链接  addBcc 添加密件抄送  addCc 添加抄送
        helper.addAttachment("测试数据.xlsx", new ClassPathResource("static/测试数据.xlsx"));

        // 发送
        javaMailSender.send(message);
    }

    /**
     * 邮箱验证码，实际需要配合 Redis 一起使用
     */
    @Test
    public void sendEmailWithCode() throws Exception {
        // 创建一个邮件信息对象，用于封装邮件信息
        MimeMessage message = javaMailSender.createMimeMessage();
        // 创建 MimeMessageHelper，指定 boolean multipart 参数为 true
        // MimeMessageHelper 对象用于帮助邮件对象设值发送参数
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        // 发件人邮箱和名称
        helper.setFrom("2320391937@qq.com", "龙茶清欢");
        // 收件人邮箱
        helper.setTo("3960981061@qq.com");
        // 邮件标题
        helper.setSubject("测试邮件发送验证码主题");
        // 生成一个6位数的随机验证码，实际需要配合 Redis 一起使用
        String verifyCode = randomUtil.verificationCode();
        // 邮件正文，第二个参数表示是否是HTML正文，我们也可以在这里放入一个精美的HTML页面
        helper.setText("Hi 2320391937@qq.com <br/>" +
                "您好，感谢您注册龙茶清欢社区账号！,您的注册验证码为：" +
                verifyCode +
                "<br/> 请尽快使用！", true);

        // 发送
        javaMailSender.send(message);
    }

    /**
     * 使用 addInline 嵌入到HTML内容中的资源
     */
    @Test
    public void sendEmailWithImage() throws Exception {
        // 创建一个邮件信息对象，用于封装邮件信息
        MimeMessage message = javaMailSender.createMimeMessage();
        // 创建 MimeMessageHelper，指定 boolean multipart 参数为 true
        // MimeMessageHelper 对象用于帮助邮件对象设值发送参数
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        // 发件人邮箱和名称
        helper.setFrom("2320391937@qq.com", "龙茶清欢");
        // 收件人邮箱
        helper.setTo("3960981061@qq.com");
        // 邮件标题
        helper.setSubject("测试邮件发送验证码主题");
        // HTML内容，包含对内联资源的引用，其中的 <img src='cid:myLogo'> 标签 cid:myLogo 和下面 addInline 对应
        String htmlContent = "<html><body>" +
                "<p>这是一封包含内联资源的HTML邮件</p>" +
                "<p>以下是嵌入的图片：<img src='cid:myLogo'></p>" +
                "</body></html>";
        // 邮件正文，第二个参数表示是否是HTML正文，我们也可以在这里放入一个精美的HTML页面
        helper.setText(htmlContent, true);
        // addInline方法添加的文件并不是附件，而是嵌入到HTML内容中的资源。可以将src属性设置为ContentID来引用这个内联资源
        helper.addInline("myLogo", new ClassPathResource("static/双人.png"));

        // 发送
        javaMailSender.send(message);
    }

    /**
     * 使用 addInline 嵌入到HTML内容中的资源
     */
    @Test
    public void sendEmailWithHtml() throws Exception {
        // 创建一个邮件信息对象，用于封装邮件信息
        MimeMessage message = javaMailSender.createMimeMessage();
        // 创建 MimeMessageHelper，指定 boolean multipart 参数为 true
        // MimeMessageHelper 对象用于帮助邮件对象设值发送参数
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        // 发件人邮箱和名称
        helper.setFrom("2320391937@qq.com", "龙茶清欢");
        // 收件人邮箱
        helper.setTo("3960981061@qq.com");
        // 邮件标题
        helper.setSubject("测试邮件发送验证码主题");
        // 生成一个6位数的随机验证码，实际需要配合 Redis 一起使用
        // String verificationCode = randomUtil.verificationCode();

        // 动态生成的HTML内容字符串
        String htmlOutput = getHtmlOutput();
        // 设置HTML内容为true，表示这是HTML格式的邮件
        helper.setText(htmlOutput, true);
        // 发送
        javaMailSender.send(message);
    }

    @Test
    @DisplayName("测试freemarker")
    public void sendEmailWithFtl() throws Exception {
        // 创建一个邮件信息对象，用于封装邮件信息
        MimeMessage message = javaMailSender.createMimeMessage();
        // 创建 MimeMessageHelper，指定 boolean multipart 参数为 true
        // MimeMessageHelper 对象用于帮助邮件对象设值发送参数
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        // 发件人邮箱和名称
        helper.setFrom("2320391937@qq.com", "龙茶清欢");
        // 收件人邮箱
        helper.setTo("3960981061@qq.com");
        // 邮件标题
        helper.setSubject("测试邮件发送验证码主题");
        // 生成一个6位数的随机验证码，实际需要配合 Redis 一起使用
        // String verificationCode = randomUtil.verificationCode();

        // 创建一个Configuration对象并设置其版本号，这个对象用来加载模板和配置模板引擎行为
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
        // 设置模板加载的位置，这里设置为类路径下的/templates目录
        cfg.setClassForTemplateLoading(MailApplicationTest.class, "/templates");
        // 获取模板对象
        Template template = cfg.getTemplate("email.ftl");
        // 创建一个包含数据模型的Map，这里ftl中需要的动态数据添加到数据模型中
        Map<String, Object> input = new HashMap<>();
        // 创建一个6位数验证码，这里我们将产品列表添加到数据模型中
        String verifyCode = randomUtil.verificationCode();
        input.put("verifyCode", verifyCode); // 将后端传递的验证码存入数据模型
        // 创建一个StringWriter对象来接收模板处理后的输出
        StringWriter stringWriter = new StringWriter();
        // 使用process方法将数据模型应用到模板上，并将结果输出到stringWriter
        template.process(input, stringWriter);
        // 从StringWriter中获取处理后的字符串，这里就是动态生成的HTML内容
        String htmlOutput = stringWriter.toString();
        // 输出生成的HTML内容到控制台
        System.out.println(htmlOutput);

        // 设置HTML内容为true，表示这是HTML格式的邮件
        helper.setText(htmlOutput, true);
        // 发送
        javaMailSender.send(message);
    }

    private static String getHtmlOutput() throws IOException, TemplateException {
        // 创建一个Configuration对象并设置其版本号，这个对象用来加载模板和配置模板引擎行为
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
        ClassLoader classLoader = Bootstrap.class.getClassLoader();
        // 设置模板加载的位置，这里设置为类路径下的/templates目录
        configuration.setClassLoaderForTemplateLoading(classLoader, "static");
        // 获取模板对象
        // 获取文件模板，可以是 html、ftl 格式，推荐使用 ftl ，ftl 是 Freemarker模板的文件后缀名
        Template template = configuration.getTemplate("email.html");
        // 利用反射构建通用Map
        Map<String, String> map = new HashMap<>();
        map.put("name", "龙茶清欢");
        map.put("email", "2320391937@qq.com");
        map.put("projectName", "龙茶清欢的应用");
        map.put("url", "www.baidu.com");
        map.put("appName", "应用名称龙茶清欢");

        // 创建一个StringWriter对象来接收模板处理后的输出
        StringWriter stringWriter = new StringWriter();
        // 使用process方法将数据模型应用到模板上，并将结果输出到stringWriter
        template.process(map, stringWriter);
        // 从StringWriter中获取处理后的字符串，这里就是动态生成的HTML内容
        String htmlOutput = stringWriter.toString();
        // 输出生成的HTML内容到控制台
        System.out.println(htmlOutput);

        return htmlOutput;
    }

}
